package com.xzj.tomcat;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xzj.spring.AnnotationApplicationContextConfig;
import com.xzj.spring.annotation.Autowired;
import com.xzj.spring.annotation.Component;
import com.xzj.springmvc.HandlerMapping;
import com.xzj.springmvc.annotation.RequestBody;
import com.xzj.springmvc.annotation.RequestParam;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.*;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.net.URI;
import java.util.*;
import java.util.function.BiFunction;
import java.util.stream.Collectors;

/**
 * @ProjectName: SpringDemo
 * @Package: com.xzj.tomcat
 * @ClassName: Tomcat
 * @Author: xzj
 * @Description: tomcat 就用来解析servlet
 * @Date: 2022/7/13 16:05
 * @Version: 1.0
 */
@Component
public class Tomcat {

    private AnnotationApplicationContextConfig applicationContext;

    private int port = 8080;

    @Autowired
    private HandlerMapping handlerMapping;

    public Tomcat() {
    }

    public Tomcat(int port) {
        this.port = port;
    }

    /**
     * @param
     * @return
     * @Author xzj
     * @Description 初始化 启动服务，接收请求， 解析http请求
     * @Date 16:35 2022/7/13
     **/
    public void init(AnnotationApplicationContextConfig applicationContext) {
        this.applicationContext = applicationContext;
        NioEventLoopGroup boss = new NioEventLoopGroup(1);
        NioEventLoopGroup worker = new NioEventLoopGroup();
        try {
            ChannelFuture channelFuture = new ServerBootstrap()
                    .group(boss, worker)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<NioSocketChannel>() {
                        @Override
                        protected void initChannel(NioSocketChannel ch) throws Exception {
                            ch.pipeline()
                                    .addLast("http-decode", new HttpRequestDecoder())
                                    .addLast("http-aggregator", new HttpObjectAggregator(65536))
                                    .addLast("http-encode", new HttpResponseEncoder())
                                    .addLast("servlet", new HttpServletHandler());
                        }
                    }).bind("localhost", port);
            channelFuture.sync().channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            try {
                boss.shutdownGracefully();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                worker.shutdownGracefully();
            }
        }
    }

    public class HttpServletHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) {
            try {
                URI uri = new URI(msg.uri());
                //获取get请求参数
                String query = uri.getQuery();
                String path = uri.getPath();
                Object bean = applicationContext.getBean((Class) HandlerMapping.getServerBean(path));
                Method method = HandlerMapping.getMethod(msg.method().name() + path);
                Object result = findServer(bean, method).apply(query, msg.content());
                //进行业务处理
                sendHttpResponse(ctx, result, HttpResponseStatus.OK);
            } catch (Exception e) {
                sendHttpResponse(ctx, e.getMessage(), HttpResponseStatus.OK);
            }
        }

        /**
         * @param ctx
         * @param result
         * @param httpResponseStatus
         * @return
         * @Author xzj
         * @Description 返回响应
         * @Date 20:40 2022/7/18
         **/
        private void sendHttpResponse(ChannelHandlerContext ctx, Object result, HttpResponseStatus httpResponseStatus) {
            DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, httpResponseStatus);
            response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html;charset=utf-8");
            response.content().writeBytes(JSON.toJSONString(result).getBytes());
            ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
        }
    }

    /**
     * @param server
     * @param method
     * @return
     * @Author xzj
     * @Description 从bean容器找到
     * @Date 9:44 2022/7/14
     **/
    public BiFunction<String, ByteBuf, Object> findServer(Object server, Method method) {
        Optional.ofNullable(server).orElseThrow(() -> new IllegalArgumentException(String.format("没有找到server: '%s' ", server)));
        Optional.ofNullable(method).orElseThrow(() -> new IllegalArgumentException(String.format("'%s'下没有找到method: '%s' ", server, method)));
        return (query, params) -> {
            try {
                return method.invoke(server, deserializationArgs(method, query, params));
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        };
    }

    /**
     * @param method
     * @param buf
     * @return
     * @Author xzj
     * @Description 反序列化参数
     * @Date 9:42 2022/7/14
     **/
    private Object[] deserializationArgs(Method method, String query, ByteBuf buf) {
        //解析请求路径消息query  此处变量名称已经编不出了，随便取了
        String[] split = query.split("&");
        Map<String, Object> queryMap = new HashMap<>();
        for (String s : split) {
            String[] split1 = s.split("=");
            queryMap.put(split1[0], split1.length > 1 ? split1[1] : null);
        }

        //解析请求体消息param
        byte[] bytes = new byte[buf.readableBytes()];
        buf.readBytes(bytes);
        Map<String, String> paramMap = JSON.parseObject(new String(bytes), Map.class);

        //方法参数类型
        Class<?>[] types = method.getParameterTypes();
        //结果集
        Object[] objects = new Object[types.length];
        //方法参数
        Parameter[] parameters = method.getParameters();

        //只能标记一次RequestBody
        boolean isRequestBody = false;

        for (int i = 0; i < parameters.length; i++) {
            //获取方法参数名称
            String[] name = new String[]{parameters[i].getName()};
            //获取请求体
            RequestBody requestBody = parameters[i].getAnnotation(RequestBody.class);
            if (requestBody != null) {
                //如果已经有标记过 抛出异常
                if (isRequestBody) {
                    throw new RuntimeException(method + "中  RequestBody 出现多次");
                }
                isRequestBody = true;
                //参数必传
                if (requestBody.required()) {
                    Optional.ofNullable(paramMap.get(name[0])).orElseThrow(() -> new RuntimeException(name[0] + "参数不能为null"));
                }
                objects[i] = converter(paramMap.get(name[0]), types[i]);
                continue;
            }

            //获取requestParam
            RequestParam requestParam = parameters[i].getAnnotation(RequestParam.class);
            if (requestParam != null) {
                //获取参数上注解定义名称
                String parameterName = requestParam.value();
                if (parameterName != null && !"".equals(parameterName.trim())) {
                    name[0] = parameterName;
                }
                //参数必传
                if (requestParam.required()) {
                    Optional.ofNullable(queryMap.get(name[0])).orElseThrow(() -> new RuntimeException(name[0] + "参数不能为null"));
                }
            }
            //检测types 是否是基本数据类型 如果是
            if (check(types[i])) {
                objects[i] = converter(queryMap.get(name[0]), types[i]);
            } else {
                //如果是引用数据类型
                objects[i] = converter(new JSONObject(queryMap), types[i]);
            }
        }
        return objects;
    }

    public boolean check(Class<?> clazz) {
        return clazz == Byte.class ||
                clazz == Boolean.class ||
                clazz == Character.class ||
                clazz == Short.class ||
                clazz == Integer.class ||
                clazz == Long.class ||
                clazz == Float.class ||
                clazz == Double.class ||
                clazz == String.class ||
                clazz == byte.class ||
                clazz == boolean.class ||
                clazz == char.class ||
                clazz == short.class ||
                clazz == int.class ||
                clazz == long.class ||
                clazz == float.class ||
                clazz == double.class;

    }

    /**
     * @param o
     * @param type
     * @return
     * @Author xzj
     * @Description 数据转换方法
     * @Date 10:39 2022/6/28
     **/
    private Object converter(Object o, Class<?> type) {
        if (o == null) {
            return null;
        }
        if (o instanceof String) {
            String s = (String) o;
            if (type == String.class) {
                return s;
            }
            if (type == Character.class) {
                return s.charAt(0);
            }
            if (type == Byte.class) {
                return Byte.valueOf(s);
            }
            if (type == Short.class) {
                return Short.valueOf(s);
            }
            if (type == Boolean.class) {
                return Boolean.valueOf(s);
            }
            if (type == Integer.class) {
                return Integer.valueOf(s);
            }
            if (type == Long.class) {
                return Long.valueOf(s);
            }
            if (type == Float.class) {
                return Float.valueOf(s);
            }
            if (type == Double.class) {
                return Double.valueOf(s);
            }
            if (type == char.class) {
                return s.charAt(0);
            }
            if (type == byte.class) {
                return Byte.valueOf(s);
            }
            if (type == boolean.class) {
                return Boolean.valueOf(s);
            }
            if (type == short.class) {
                return Short.valueOf(s);
            }
            if (type == int.class) {
                return Integer.valueOf(s);
            }
            if (type == long.class) {
                return Long.valueOf(s);
            }
            if (type == float.class) {
                return Float.valueOf(s);
            }
            if (type == double.class) {
                return Double.valueOf(s);
            }
        }
        //如果不是基本数据类型，是引用数据类型，那么就拆开来递归调用
        if (o instanceof JSONObject) {
            try {
                Map<String, Object> map = (Map<String, Object>) o;
                Field[] fields = type.getDeclaredFields();
                //创建实例
                Object obj = type.newInstance();
                List<String> fieldNames = Arrays.stream(fields).map(x -> x.getName()).collect(Collectors.toList());
                Class[] clz = Arrays.stream(fields).map(x -> x.getType()).collect(Collectors.toList()).toArray(new Class[0]);
                Object[] values = new Object[clz.length];
                for (int i = 0; i < clz.length; i++) {
                    values[i] = converter(map.get(fieldNames.get(i)), clz[i]);
                }
                for (int i = 0; i < values.length; i++) {
                    //如果没有值的直接跳过
                    if (values[i] == null) {
                        continue;
                    }
                    //有值的用反射赋值
                    fields[i].setAccessible(true);
                    fields[i].set(obj, values[i]);
                }
                return obj;
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

}
